package gupao.concurrency.demo;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class WaitNotifyDemo {

    public static void main(String[] args) throws InterruptedException {
        WaitNotifyDemo demo = new WaitNotifyDemo();
        new Thread(new Producer(demo)).start();
        new Thread(() -> {
            while(!demo.stop){
                demo.consume();
            }
        }).start();

        TimeUnit.SECONDS.sleep(10);
        demo.stop = true;
    }

    volatile boolean stop = false;
    int productNumber = 0;//产品编号记录
    private Product product;

    public synchronized void produce(){
        while(product != null){
            log.warn("等待产品被消费掉先..");
            try {
                wait();
            } catch (InterruptedException e) {
                //ignore
            }
        }
        productNumber++;
        log.info("产品({})开始生产", productNumber);
        sleepIgnoreExp(1000);
        product = new Product(productNumber);
        log.info("产品({})已经生产好，请自取", productNumber);
        notifyAll();
    }

    public synchronized void consume(){
        while(product == null){
            log.warn("没有产品可以消费, 等待..");
            try {
                wait();
            } catch (InterruptedException e) {
                //ignore
            }
        }
        log.info("产品({})已拿到，开始享用.", product.number);
        sleepIgnoreExp(1000);
        log.info("产品({})已消费.", product.number);
        product = null;
        notifyAll();
    }

    @AllArgsConstructor
    static class Product{
        int number;
    }

    @AllArgsConstructor
    static class Producer implements Runnable{
        private final WaitNotifyDemo demo;
        @Override
        public void run() {
            while(!demo.stop) {
                demo.produce();
            }
        }
    }

    static void sleepIgnoreExp(long milli){
        try {
            TimeUnit.MILLISECONDS.sleep(milli);
        } catch (InterruptedException e) {
        }
    }
}
